package com.google.code.tretris.rendering;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

import com.google.code.tretris.common.Tetromino;
import com.google.code.tretris.common.WKC;
import com.google.code.tretris.events.MoveEvent;
import com.google.code.tretris.events.UpdateBoardEvent;
import com.google.code.tretris.network.game.GameActionListener;

public class TretrisRenderer implements Renderer, GameActionListener {

	private final static String LOG_TAG = TretrisRenderer.class.getName();
	
	private final FPSCounter counters = new FPSCounter();
	private final Camera camera = new Camera();
	private final Light light = new Light(GL10.GL_LIGHT0, true);
	private final ConcurrentHashMap<Integer, MVComplexObject> inactiveTetronimos = new ConcurrentHashMap<Integer, MVComplexObject>(249);
	private final Shape activeShape;
	private final int halfTheBoardWidth = WKC.BOARD_WIDTH / 2;
	private final int halfTheBoardHeight = WKC.BOARD_HEIGHT / 2;

	//	private Scene scene;

	public TretrisRenderer(final Shape activeShape) {
		//scene = new Scene(clientId);
		this.activeShape = activeShape;
	}

	public void onDrawFrame(GL10 gl) {
		final long now = System.currentTimeMillis();
		counters.now(now);

		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadIdentity();

		light.render(gl);

		camera.render(gl);

		activeShape.render(gl);		
		for (Renderable inactive : inactiveTetronimos.values()) {
			inactive.render(gl);
		}

		counters.framecount++;
	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {

		gl.glViewport(0, 0, width, height);
		camera.setupProjection(gl, width, height);	
	}

	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
		gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glClearDepthf(1.0f);

		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glEnable(GL10.GL_RESCALE_NORMAL);

		// Counter-clockwise winding.
		gl.glFrontFace(GL10.GL_CCW);
		// Enable face culling.
		gl.glEnable(GL10.GL_CULL_FACE);
		// What faces to remove with the face culling.
		gl.glCullFace(GL10.GL_BACK);
		gl.glShadeModel(GL10.GL_SMOOTH);

		// Setup light 0
		light.initialize(gl);
		light.setPosition(70, 70, -10);

		camera.setPosition(10, 35, 90);

	}


	public void move(MoveEvent e) {

	}

	public void rotate(MoveEvent e) {

	}

	public void update(final List<UpdateBoardEvent> events) {
		for (UpdateBoardEvent event : events) {
			update(event);
		}
	}

	public synchronized void update(final UpdateBoardEvent e) {
		if (activeShape != null) {
			activeShape.update(e);
		}
		int blocks[] = e.getBlocks();
		for (int i = 0; i < blocks.length; i++) {
			if (blocks[i] != 0 && i < 240 && !inactiveTetronimos.containsKey(i)) {
				float[] color = Tetromino.COLORS.get(blocks[i]);
				Cube cube = new Cube(Cube.DEFAULT_WIDTH);
				cube.setColor(color[0], color[1], color[2]);
				
				int row = i / WKC.BOARD_WIDTH;
				int col = i - (WKC.BOARD_WIDTH * row);
				 
				cube.setPosition(-halfTheBoardWidth + (col * Cube.DEFAULT_OFFSET),
								-halfTheBoardHeight + (row * Cube.DEFAULT_OFFSET), 0);
				inactiveTetronimos.put(i, cube);
			}
		}
	}

	private static class FPSCounter {
		private static final long FPS_EMIT_INTERVAL = 10000;
		private long framecount = 0;
		private long previousfpsemit = System.currentTimeMillis();
		private long nextfpsemit = System.currentTimeMillis()
		+ FPS_EMIT_INTERVAL;

		private void now(final long now) {
			if (now > nextfpsemit) {
				final long timesincelastfpsemit = now - previousfpsemit;
				Log.d(LOG_TAG,
						((float) framecount / (float) timesincelastfpsemit)
						* 1000 + " FPS");
				framecount = 0;
				previousfpsemit = now;
				nextfpsemit = now + FPSCounter.FPS_EMIT_INTERVAL;
			}
		}
	}
}
